package com.gitee.wsl.mathematics.vector.vec4

import com.gitee.wsl.mathematics.vector.MutableVector
import com.gitee.wsl.mathematics.vector.MutableVectorD
import com.gitee.wsl.mathematics.vector.MutableVectorF
import com.gitee.wsl.mathematics.vector.update
import com.gitee.wsl.mathematics.vector.vec2.MutableVector2
import com.gitee.wsl.mathematics.vector.vec3.MutableVector3

typealias MutableVec4F = MutableVector4<Float,*>

typealias MutableVec4D = MutableVector4<Double,*>

interface MutableVector4<T:Number,V: Vector4<T, V>>: Vector4<T, V>, MutableVector<T, V> {

    //override val vec2: MutableVector2<T, *>
    //override val vec3: MutableVector3<T, *>
    //override val vec4: MutableVector4<T, *>

    override fun createVec2(a:T, b:T): MutableVector2<T, *>

    override fun createVec3(a:T, b:T, c:T): MutableVector3<T, *>

    override var x
        get() = proxy[0]
        set(value) {
            proxy[0] = value
        }

    override var y
        get() = proxy[1]
        set(value) {
            proxy[1] = value
        }

    override var z
        get() = proxy[2]
        set(value) {
            proxy[2] = value
        }

    override var w
        get() = proxy[3]
        set(value) {
            proxy[3] = value
        }

    override var length
        get() = sqrt(squaredLength)
        set(value) {
            val newVec = normalized * value
            x = newVec.x
            y = newVec.y
            z = newVec.z
            w = newVec.w
        }

    /*override operator fun plusAssign(other: V) {
        x += other.x
        y += other.y
        z += other.z
        w += other.w
    }

    override operator fun timesAssign(other: V) {
        x *= other.x
        y *= other.y
        z *= other.z
        w *= other.w
    }

    override operator fun divAssign(other: V) {
        x /= other.x
        y /= other.y
        z /= other.z
        w /= other.w
    }

    override fun subtract(other: V) {
        x -= other.x
        y -= other.y
        z -= other.z
        w -= other.w
    }

    override fun scale(factor: T) {
        x *= factor
        y *= factor
        z *= factor
        w *= factor
    }

    fun set(x:T,y:T,z:T,w:T){
        this.x=x
        this.y=y
        this.z=z
        this.w=w
    }*/

    fun set(x:Number,y:Number,z:Number,w:Number){
        this.x += x
        this.y += y
        this.z += z
        this.w += w
    }

    //override fun set(other: V) = set(other.x,other.y,other.z,other.z)

    fun set(other: Vector4<T, *>) = set(other.x,other.y,other.z,other.z)


    fun subtract(other: Vector4<T, *>) {
        x -= other.x
        y -= other.y
        z -= other.z
        w -= other.w
    }


    /**
     * Multiplies this vector as a quaternion with another in the form of `other * this`.
     *
     * @param otherQuat the quaternion to multiply with
     */
    fun quatMulLeft(otherQuat: Vector4<T, *>) = update{
        val px = otherQuat.w * x + otherQuat.x * w + otherQuat.y * z - otherQuat.z * y
        val py = otherQuat.w * y + otherQuat.y * w + otherQuat.z * x - otherQuat.x * z
        val pz = otherQuat.w * z + otherQuat.z * w + otherQuat.x * y - otherQuat.y * x
        val pw = otherQuat.w * w - otherQuat.x * x - otherQuat.y * y - otherQuat.z * z
        set(px, py, pz, pw)
    }

    /*override fun negate() {
        x *= -1f
        y *= -1f
        z *= -1f
        w *= -1f
    }*/
}




interface MutableVector4F<V: Vector4<Float, V>> : MutableVector4<Float, V>, MutableVectorF<V>{

}

interface MutableVector4D<V: Vector4<Double, V>> : MutableVector4<Double, V>, MutableVectorD<V>{

    /*override val vec2 get() = MutableVec2(x, y)
    override val vec3 get() = MutableVec3(x, y, z)
    override val vec4 get() = this

    override val xy get() = MutableVec2(x, y)
    override val xz get() = MutableVec2(x, z)
    override val xw get() = MutableVec2(x, w)
    override val yz get() = MutableVec2(y, z)
    override val yw get() = MutableVec2(y, w)
    override val zw get() = MutableVec2(z, w)
    override val xyz get() = MutableVec3(x, y, z)
    override val xyw get() = MutableVec3(x, y, w)
    override val xzw get() = MutableVec3(x, z, w)
    override val yzw get() = MutableVec3(y, z, w)*/

}